package com.tools.web.interceptor.quota;

import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisPlus;

/**
 * 使用 JedisPlus 客户端操作单机 Redis 实现配额限制拦截器
 * 【注意】：业务成功后必须通过该拦截器实例的 incrSuccessfulCount 方法进行次数自增。
 * */
@Note("使用 JedisPlus 客户端操作单机 Redis 实现配额限制拦截器." +
        "【注意】：业务成功后必须通过该拦截器实例的 incrSuccessfulCount 方法进行次数自增。")
public final class JedisPlusQuotaInterceptor extends QuotaInterceptor {

    @Note("JedisPlus 操作单机 Redis 的客户端实例")
    private final JedisPlus cache;

    public JedisPlusQuotaInterceptor(JedisPlus cache, QuotaSource source) {
        super(source, cache != null, "JedisPlus 客户端实例不能为 null");
        this.cache = cache;
    }


    @Override
    public void incrSuccessfulCount(String uniqueID, String action, long createExpiration, Timeunit createTimeunit) {
        if(createExpiration < 1) return;
        if(createTimeunit == null) throw new NullPointerException("过期时间单位为 null");
        String key = super.protected_getCachePrefix() + action + ':' + uniqueID;
        try {
            synchronized (key) {
                Integer successFulCount = this.protected_getSuccessfulCount(key);
                if(successFulCount == null) {
                    this.cache.jedis().setex(key,
                            Timeunit.toSecond(createExpiration, createTimeunit), Integer.toString(1));
                    return;
                }
                long ttl = this.cache.ttl(key);
                if(ttl < 1) {
                    this.cache.jedis().setex(key,
                            Timeunit.toSecond(createExpiration, createTimeunit), Integer.toString(1));
                    return;
                }
                this.cache.jedis().setex(key, ttl, Integer.toString(successFulCount + 1));
            }
        } finally {
            this.cache.close();
        }
    }

    @Override
    protected Integer protected_getSuccessfulCount(String key) {
        try {
            String s = this.cache.jedis().get(key);
            return (s == null) ? null : Integer.parseInt(s);
        } catch (Exception e) {
            this.cache.close();
            throw e;
        }
    }

    @Override
    protected long protected_getRemainder(String key) {
        return this.cache.ttl$(key);
    }
}
